package com.hb.unic.core.expression;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;

/**
 * spel表达式解析器
 *
 * @since v1.0，2023/8/31 19:38，create by Mr.Huang.
 */
public class SpelMessageEvaluator {

    /**
     * 解析器
     */
    private static final ExpressionParser PARSE = new SpelExpressionParser();

    /**
     * 缓存
     */
    private static final Map<Method, Expression> CACHE = new ConcurrentHashMap<>();

    /**
     * 参数名解析工具
     */
    private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER =
        new LocalVariableTableParameterNameDiscoverer();

    /**
     * 解析spel表达式
     * 
     * @param messageTemplate 包含spel表达式的内容
     * @param method 方法名
     * @param args 方法参数
     * @return 结果
     */
    public static String evaluateString(String messageTemplate, Method method, Object[] args) {
        return String.valueOf(evaluate(messageTemplate, method, args));
    }

    /**
     * 解析spel表达式
     * 
     * @param messageTemplate 包含spel表达式的内容
     * @param method 方法名
     * @param args 方法参数
     * @return 结果
     */
    public static Object evaluate(String messageTemplate, Method method, Object[] args) {
        // 没有表达式，不解析，直接返回
        if (StringUtils.isEmpty(messageTemplate)
            || !messageTemplate.contains(ParserContext.TEMPLATE_EXPRESSION.getExpressionPrefix())) {
            return messageTemplate;
        }
        // 获取表达式，先从缓存中取，提高性能
        Expression expression = CACHE.get(method);
        if (expression == null) {
            expression = PARSE.parseExpression(messageTemplate, ParserContext.TEMPLATE_EXPRESSION);
            CACHE.put(method, expression);
        }
        // 获取方法参数名
        String[] parameterNames = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
        if (parameterNames == null || parameterNames.length == 0 || args == null
            || parameterNames.length != args.length) {
            return messageTemplate;
        }
        Map<String, Object> rootObject = new HashMap<>();
        for (int i = 0; i < parameterNames.length; i++) {
            rootObject.put(parameterNames[i], args[i]);
        }
        // 解析spel表达式
        EvaluationContext context = new StandardEvaluationContext(rootObject);
        return expression.getValue(context);
    }

}
